Skip to content

fix: check quoted text for content safety#9232

Open
2409324124 wants to merge 2 commits into
AstrBotDevs:masterfrom
2409324124:fix/quoted-message-content-safety
Open

fix: check quoted text for content safety#9232
2409324124 wants to merge 2 commits into
AstrBotDevs:masterfrom
2409324124:fix/quoted-message-content-safety

Conversation

@2409324124

@2409324124 2409324124 commented Jul 13, 2026

Copy link
Copy Markdown

Summary

  • check quoted message text during inbound content safety validation
  • reuse the existing ReplyChainParser for both embedded chains and message_str
  • keep explicit response checks isolated from the original quoted input

Root cause

The content safety stage only checked event.get_message_str(), while quoted text was stored in Reply components and later added to the LLM request. This allowed blocked keywords to reach the model when they appeared only in a quoted message.

Quoted text is checked separately from the current message so regular-expression anchors such as ^...$ keep their existing semantics.

Closes #9227.

Validation

  • uv run ruff format --check .
  • uv run ruff check .
  • uv run pytest -q tests/test_content_safety_check.py tests/test_quoted_message_parser.py tests/unit/test_aiocqhttp_reply.py tests/unit/test_astr_message_event.py tests/test_smoke.py (121 passed)

The complete test suite was also attempted, but the unrelated existing test test_dify_image_upload_uses_media_resolver_for_data_url hangs when run in isolation in this environment.

Summary by Sourcery

Validate inbound content safety against both the main message text and any quoted reply text to prevent blocked keywords from reaching the model.

Bug Fixes:

  • Fix omission where quoted reply text was not checked by content safety, allowing blocked keywords to bypass filters.

Enhancements:

  • Ensure explicit check_text overrides skip quoted-text parsing so existing anchor-based regex rules retain their semantics.

Tests:

  • Add content safety tests covering quoted reply text, including chain-based replies, regex-anchored keywords, and explicit check_text overrides.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the content safety check stage to extract and verify quoted text from reply components when no explicit check text is provided, and adds corresponding unit tests. A potential issue was identified where the variables ok and info are defined inside a loop over texts; if texts is empty, this could lead to a NameError when they are accessed after the loop. Initializing these variables before the loop is recommended.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +44 to 48
for text in texts:
ok, info = self.strategy_selector.check(text)
if not ok:
break
if not ok:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variables ok and info are defined inside the for text in texts: loop. If texts is empty (or from the perspective of static type checkers like mypy or pyright which cannot guarantee the list is non-empty), these variables will be unbound when accessed on line 48 and line 57, leading to a potential NameError or type-checking failures.

Initializing ok and info before the loop resolves this issue and makes the code more robust.

        ok, info = True, ""
        for text in texts:
            ok, info = self.strategy_selector.check(text)
            if not ok:
                break
        if not ok:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 24b1d1a by initializing ok and info before the loop. Repository-wide Ruff checks pass, along with the related regression suite (121 passed). Thank you.

Copy link
Copy Markdown
Author

/gemini Please review the latest changes. Commit 24b1d1a addresses the unbound-variable feedback from the previous review.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the content safety check stage to also inspect quoted text within reply components of incoming messages. It introduces the ReplyChainParser to extract text from replies and iterates through all extracted texts to perform safety checks. Additionally, unit tests have been added to verify this behavior. The review feedback suggests skipping empty or whitespace-only strings during the safety check loop to prevent redundant external API calls and reduce latency.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +44 to +48
ok, info = True, ""
for text in texts:
ok, info = self.strategy_selector.check(text)
if not ok:
break

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If texts contains empty or whitespace-only strings (for example, if the user sends an image/file without text, or if check_text is passed as an empty string), calling self.strategy_selector.check(text) will still execute. If external content safety APIs (like Baidu AIP) are enabled, this will result in unnecessary network requests, which increases latency and can incur API usage costs.

We should skip empty or whitespace-only strings in the loop to avoid these redundant checks.

Suggested change
ok, info = True, ""
for text in texts:
ok, info = self.strategy_selector.check(text)
if not ok:
break
ok, info = True, ""
for text in texts:
if not text or not text.strip():
continue
ok, info = self.strategy_selector.check(text)
if not ok:
break

texts = [check_text]

ok, info = True, ""
for text in texts:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi, join these text parts and check once is enough

@Soulter
Soulter marked this pull request as ready for review July 18, 2026 10:38
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend labels Jul 18, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]屏蔽词可以通过引用绕过

2 participants